package com._119yn.host.gst200.service.impl;

import com._119yn.host.gst200.constant.PointTable;
import com._119yn.host.gst200.constant.SysAttrs;
import com._119yn.host.gst200.database.dao.PointTableRecordDao;
import com._119yn.host.gst200.database.entity.PointTableRecord;
import com._119yn.host.gst200.event.PointTableImportedEvent;
import com._119yn.host.gst200.properties.DtuProperties;
import com._119yn.host.gst200.service.PointTableService;
import com._119yn.host.gst200.service.SysAttrService;
import com._119yn.host.gst200.utils.PointTableRecordUtils;
import lombok.RequiredArgsConstructor;
import lombok.Synchronized;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.nio.file.Path;
import java.util.Collection;
import java.util.List;

@Slf4j
@Service
@RequiredArgsConstructor
public class PointTableServiceImpl implements PointTableService {

    private final DtuProperties properties;

    private final PointTableRecordDao pointTableRecordDao;

    private final ApplicationEventPublisher applicationEventPublisher;

    private final SysAttrService sysAttrService;

    @Override
    public boolean isImported() {
        return sysAttrService.getBoolean(SysAttrs.POINT_TABLE_IMPORTED);
    }

    @Synchronized
    @Transactional
    public void importPointTable() throws RuntimeException {
        if (isImported()) {
            log.warn("设备点表已加载，请勿重复加载");
            return;
        }
        String filePath = properties.getDevicePointTableFile();
        if (StringUtils.isBlank(filePath)) {
            return;
        }
        File file = Path.of(filePath).toFile();
        if (!file.exists()) {
            throw new RuntimeException(new FileNotFoundException(filePath));
        }
        try (InputStream inputStream = new FileInputStream(file)) {
            Charset fileCharset = Charset.forName("GBK");
            importPointTable(PointTableRecordUtils.parse(inputStream, fileCharset));
        } catch (Exception e) {
            log.warn("设备点表加载失败: {}", e.getMessage());
            System.exit(-1);
        }
    }

    @Synchronized
    @Transactional
    @Override
    public void importPointTable(List<PointTableRecord> pointTableRecords) {
        if (pointTableRecords == null) {
            return;
        }

        // 清空点表记录
        pointTableRecordDao.truncate();

        if (pointTableRecords.isEmpty()) {
            // 设置点表导入完成标志
            sysAttrService.putBoolean(SysAttrs.POINT_TABLE_IMPORTED, false);
        } else {
            // 批量插入点表记录数据
            pointTableRecordDao.insertBatch(pointTableRecords);

            // 设置点表导入完成标志
            sysAttrService.putBoolean(SysAttrs.POINT_TABLE_IMPORTED, true);

            // 发布点表导入完成事件
            applicationEventPublisher.publishEvent(PointTableImportedEvent.INSTANCE);
        }
    }

    @Override
    public PointTableRecord getByPanelAndDeviceAddressAndDeviceType(int panel, int deviceAddress, int deviceType) {
        return pointTableRecordDao.selectByPanelAndDeviceAddressAndDeviceType(panel, getStandardDevCode(deviceAddress), getStandardDevType(deviceType));
    }

    @Override
    public PointTableRecord getByPanelAndDeviceAddressAndDeviceType(int panel, String deviceAddress, String deviceType) {
        return pointTableRecordDao.selectByPanelAndDeviceAddressAndDeviceType(panel, deviceAddress, deviceType);
    }

    @Override
    public PointTableRecord getByDeviceId(String deviceId) {
        return pointTableRecordDao.selectByDeviceId(deviceId);
    }

    @Override
    public List<PointTableRecord> getAllControllers() {
        return pointTableRecordDao.selectByDeviceTypeIn(PointTableRecordUtils.CONTROLLER_TYPES);
    }

    @Override
    public List<PointTableRecord> getDeviceByPanel(Collection<Integer> hostIds) {
        return pointTableRecordDao.selectByPanelIn(hostIds);
    }

    @Override
    public String getStandardDevCode(int devCode) {
        return "%06d".formatted(devCode);
    }

    @Override
    public String getStandardDevType(int devType) {
        return "%d".formatted(devType);
    }

    @Override
    public PointTableRecord getDtu() {
        PointTableRecord pointTableRecord = pointTableRecordDao.selectByDeviceType(PointTable.DTU_DEVICE_TYPE);
        if (pointTableRecord == null) {
            return null;
        }
        return pointTableRecord;
    }

    @Override
    public String getDtuDeviceId() {
        PointTableRecord pointTableRecord = pointTableRecordDao.selectByDeviceType(PointTable.DTU_DEVICE_TYPE);
        if (pointTableRecord == null) {
            return null;
        }
        return pointTableRecord.getDeviceId();
    }

    @Override
    public String getDtuDeviceAddress() {
        PointTableRecord pointTableRecord = pointTableRecordDao.selectByDeviceType(PointTable.DTU_DEVICE_TYPE);
        if (pointTableRecord == null) {
            return null;
        }
        return pointTableRecord.getDeviceAddress();
    }

    @Override
    public List<PointTableRecord> getAll() {
        return pointTableRecordDao.selectAll();
    }

}
